(defpackage :lem-vi-mode/tests/motion
  (:use :cl
        :lem
        :rove
        :lem-vi-mode/tests/utils)
  (:import-from :lem-fake-interface
                :with-fake-interface)
  (:import-from :named-readtables
                :in-readtable))
(in-package :lem-vi-mode/tests/motion)

(in-readtable :interpol-syntax)

(deftest vi-forward-char
  (with-fake-interface ()
    (with-vi-buffer (#?"[a]bcdef\n")
      (cmd "l")
      (ok (buf= #?"a[b]cdef\n"))
      (cmd "3l")
      (ok (buf= #?"abcd[e]f\n"))
      (cmd "10l")
      (ok (buf= #?"abcde[f]\n")))
    (with-vi-buffer (#?"abc\n[]\ndef")
      (cmd "l")
      (ok (buf= #?"abc\n[]\ndef")))))

(deftest vi-forward-word-end
  (with-fake-interface ()
    (with-vi-buffer (#?"[a]bc()def#ghi jkl ()\n")
      (cmd "e")
      (ok (buf= #?"ab[c]()def#ghi jkl ()\n"))
      (cmd "e")
      (ok (buf= #?"abc([)]def#ghi jkl ()\n"))
      (cmd "e")
      (ok (buf= #?"abc()de[f]#ghi jkl ()\n"))
      (cmd "e")
      (ok (buf= #?"abc()def[#]ghi jkl ()\n"))
      (cmd "e")
      (ok (buf= #?"abc()def#gh[i] jkl ()\n"))
      (cmd "2e")
      (ok (buf= #?"abc()def#ghi jkl ([)]\n"))
      (cmd "e")
      (ok (buf= #?"abc()def#ghi jkl ()\n[]"))
      (cmd "10e")
      (ok (buf= #?"abc()def#ghi jkl ()\n[]")))
    (with-vi-buffer (#?"[a]bc def () \n\t # ghi\n")
      (cmd "e")
      (ok (buf= #?"ab[c] def () \n\t # ghi\n"))
      (cmd "e")
      (ok (buf= #?"abc de[f] () \n\t # ghi\n"))
      (cmd "e")
      (ok (buf= #?"abc def ([)] \n\t # ghi\n"))
      (cmd "e")
      (ok (buf= #?"abc def () \n\t [#] ghi\n"))
      (cmd "e")
      (ok (buf= #?"abc def () \n\t # gh[i]\n")))
    (with-vi-buffer (#?"abc [ ]\t def\n\n ghi")
      (cmd "e")
      (ok (buf= #?"abc  \t de[f]\n\n ghi"))
      (cmd "l")
      (cmd "e")
      (ok (buf= #?"abc  \t def\n\n gh[i]")))
    (with-vi-buffer (#?"a[b]cd efg hij klm nop")
      (cmd "de")
      (ok (buf= #?"a[ ]efg hij klm nop"))
      (cmd "de")
      (ok (buf= #?"a[ ]hij klm nop"))
      (cmd "d2e")
      (ok (buf= #?"a[ ]nop")))))

(deftest vi-forward-word-end-broad
  (with-fake-interface ()
    (with-vi-buffer (#?"[a]bc-def (ghi jkl) # \n\t m")
      (cmd "E")
      (ok (buf= #?"abc-de[f] (ghi jkl) # \n\t m"))
      (cmd "E")
      (ok (buf= #?"abc-def (gh[i] jkl) # \n\t m"))
      (cmd "E")
      (ok (buf= #?"abc-def (ghi jkl[)] # \n\t m"))
      (cmd "E")
      (ok (buf= #?"abc-def (ghi jkl) [#] \n\t m"))
      (cmd "E")
      (ok (buf= #?"abc-def (ghi jkl) # \n\t [m]"))
      (cmd "E")
      (ok (buf= #?"abc-def (ghi jkl) # \n\t [m]"))
      (cmd "gg")
      (cmd "3E")
      (ok (buf= #?"abc-def (ghi jkl[)] # \n\t m")))
    (with-vi-buffer ("ab[c]-def ghi # jkl")
      (cmd "dE")
      (ok (buf= "ab[ ]ghi # jkl"))
      (cmd "d2E")
      (ok (buf= "ab[ ]jkl")))))

(deftest vi-backward-word-begin
  (with-fake-interface ()
    (with-vi-buffer (#?"abc()def#ghi jkl ()[\n]")
      (cmd "b")
      (ok (buf= #?"abc()def#ghi jkl [(])\n"))
      (cmd "2b")
      (ok (buf= #?"abc()def#[g]hi jkl ()\n"))
      (cmd "b")
      (ok (buf= #?"abc()def[#]ghi jkl ()\n"))
      (cmd "b")
      (ok (buf= #?"abc()[d]ef#ghi jkl ()\n"))
      (cmd "b")
      (ok (buf= #?"abc[(])def#ghi jkl ()\n"))
      (cmd "b")
      (ok (buf= #?"[a]bc()def#ghi jkl ()\n"))
      (cmd "10b")
      (ok (buf= #?"[a]bc()def#ghi jkl ()\n")))
    (with-vi-buffer (#?"abc def () \n\t # ghi[\n]")
      (cmd "b")
      (ok (buf= #?"abc def () \n\t # [g]hi\n"))
      (cmd "b")
      (ok (buf= #?"abc def () \n\t [#] ghi\n"))
      (cmd "b")
      (ok (buf= #?"abc def [(]) \n\t # ghi\n"))
      (cmd "b")
      (ok (buf= #?"abc [d]ef () \n\t # ghi\n"))
      (cmd "b")
      (ok (buf= #?"[a]bc def () \n\t # ghi\n")))
    (with-vi-buffer (#?"abc\n\n  \t de[f]")
      (cmd "b")
      (ok (buf= #?"abc\n\n  \t [d]ef"))
      (cmd "h")
      (cmd "b")
      (ok (buf= #?"[a]bc\n\n  \t def")))
    (with-vi-buffer ("abc # def-g[h]i")
      (cmd "db")
      (ok (buf= "abc # def-[h]i"))
      (cmd "d2b")
      (ok (buf= "abc # [h]i")))))

(deftest vi-backward-word-begin-broad
  (with-fake-interface ()
    (with-vi-buffer (#?"a \t\n # (bcd efg) hij-kl[m]")
      (cmd "B")
      (ok (buf= #?"a \t\n # (bcd efg) [h]ij-klm"))
      (cmd "B")
      (ok (buf= #?"a \t\n # (bcd [e]fg) hij-klm"))
      (cmd "B")
      (ok (buf= #?"a \t\n # [(]bcd efg) hij-klm"))
      (cmd "B")
      (ok (buf= #?"a \t\n [#] (bcd efg) hij-klm"))
      (cmd "B")
      (ok (buf= #?"[a] \t\n # (bcd efg) hij-klm"))
      (cmd "G$")
      (cmd "3B")
      (ok (buf= #?"a \t\n # [(]bcd efg) hij-klm")))
    (with-vi-buffer ("jkl # ghi abc-[d]ef")
      (cmd "dB")
      (ok (buf= "jkl # ghi [d]ef"))
      (cmd "d2B")
      (ok (buf= "jkl [d]ef")))))

(deftest vi-forward-word-begin
  (with-fake-interface ()
    (with-vi-buffer (#?"[a]bc()def#ghi jkl ()\n")
      (cmd "w")
      (ok (buf= #?"abc[(])def#ghi jkl ()\n"))
      (cmd "w")
      (ok (buf= #?"abc()[d]ef#ghi jkl ()\n"))
      (cmd "w")
      (ok (buf= #?"abc()def[#]ghi jkl ()\n"))
      (cmd "w")
      (ok (buf= #?"abc()def#[g]hi jkl ()\n"))
      (cmd "2w")
      (ok (buf= #?"abc()def#ghi jkl [(])\n"))
      (cmd "10w")
      (ok (buf= #?"abc()def#ghi jkl ()\n[]")))
    (with-vi-buffer (#?"[a]bc def () \n\t # ghi\n")
      (cmd "w")
      (ok (buf= #?"abc [d]ef () \n\t # ghi\n"))
      (cmd "w")
      (ok (buf= #?"abc def [(]) \n\t # ghi\n"))
      (cmd "w")
      (ok (buf= #?"abc def () \n\t [#] ghi\n"))
      (cmd "w")
      (ok (buf= #?"abc def () \n\t # [g]hi\n"))
      (cmd "w")
      (ok (buf= #?"abc def () \n\t # ghi\n[]")))
    (with-vi-buffer (#?"abc [ ]\t def\n\n ghi")
      (cmd "w")
      (ok (buf= #?"abc  \t [d]ef\n\n ghi"))
      (cmd "3l")
      (cmd "w")
      (ok (buf= #?"abc  \t def\n\n [g]hi")))
    (with-vi-buffer (#?"a[b]cd efg hij klm nop")
      (cmd "dw")
      (ok (buf= #?"a[e]fg hij klm nop"))
      (cmd "dw")
      (ok (buf= #?"a[h]ij klm nop"))
      (cmd "d2w")
      (ok (buf= #?"a[n]op")))))

(deftest vi-forward-word-begin-broad
  (with-fake-interface ()
    (with-vi-buffer (#?"[a]bc-def (ghi jkl) # \n\t m")
      (cmd "W")
      (ok (buf= #?"abc-def [(]ghi jkl) # \n\t m"))
      (cmd "W")
      (ok (buf= #?"abc-def (ghi [j]kl) # \n\t m"))
      (cmd "W")
      (ok (buf= #?"abc-def (ghi jkl) [#] \n\t m"))
      (cmd "W")
      (ok (buf= #?"abc-def (ghi jkl) # \n\t [m]"))
      (cmd "W")
      (ok (buf= #?"abc-def (ghi jkl) # \n\t [m]"))
      (cmd "gg")
      (cmd "3W")
      (ok (buf= #?"abc-def (ghi jkl) [#] \n\t m")))
    (with-vi-buffer ("ab[c]-def ghi # jkl")
      (cmd "dW")
      (ok (buf= "ab[g]hi # jkl"))
      (cmd "d2W")
      (ok (buf= "ab[j]kl")))))

(deftest vi-move-to-end-of-line
  (with-fake-interface ()
    (lem:window-set-size (lem:current-window) 5 24)
    (with-vi-buffer (#?"[a]bcdefgh\nijklmn\n")
      (cmd "$")
      (ok (buf= #?"abcdefg[h]\nijklmn\n")))
    (with-vi-buffer (#?"[a]bc\ndef\nghi\njkl\n")
      (cmd "3$")
      (ok (buf= #?"abc\ndef\ngh[i]\njkl\n")))))

(deftest vi-goto-line
  (with-fake-interface ()
    (with-vi-buffer (#?"abc\ndef\nghi\nj[k]l\n")
      (cmd "gg")
      (ok (buf= #?"a[b]c\ndef\nghi\njkl\n"))
      (cmd "3gg")
      (ok (buf= #?"abc\ndef\ng[h]i\njkl\n"))
      (cmd "G")
      (ok (buf= #?"abc\ndef\nghi\nj[k]l\n"))
      (cmd "2G")
      (ok (buf= #?"abc\nd[e]f\nghi\njkl\n")))))

(deftest vi-find-char
  (with-fake-interface ()
    (with-vi-buffer ("[f]oo-bar-Baz")
      (cmd "f-")
      (ok (buf= "foo[-]bar-Baz"))
      (cmd "fB")
      (ok (buf= "foo-bar-[B]az"))
      (cmd "^2f-")
      (ok (buf= "foo-bar[-]Baz"))
      (cmd "^3fa")
      (ok (buf= "[f]oo-bar-Baz"))
      (cmd ";")
      (ok (buf= "foo-b[a]r-Baz"))
      (cmd "^2;")
      (ok (buf= "foo-bar-B[a]z")))))

(deftest vi-find-char-before
  (with-fake-interface ()
    (with-vi-buffer ("[f]oo-bar-Baz")
      (cmd "t-")
      (ok (buf= "fo[o]-bar-Baz"))
      (cmd "tB")
      (ok (buf= "foo-bar[-]Baz"))
      (cmd "^2t-")
      (ok (buf= "foo-ba[r]-Baz"))
      (cmd "^3ta")
      (ok (buf= "[f]oo-bar-Baz"))
      (cmd ";")
      (ok (buf= "foo-[b]ar-Baz"))
      (cmd "^2;")
      (ok (buf= "foo-bar-[B]az")))))

(deftest vi-find-char-backward
  (with-fake-interface ()
    (with-vi-buffer ("foo-bar-Ba[z]")
      (cmd "F-")
      (ok (buf= "foo-bar[-]Baz"))
      (cmd "$Fb")
      (ok (buf= "foo-[b]ar-Baz"))
      (cmd "$2F-")
      (ok (buf= "foo[-]bar-Baz"))
      (cmd "$3Fa")
      (ok (buf= "foo-bar-Ba[z]"))
      (cmd ";")
      (ok (buf= "foo-bar-B[a]z"))
      (cmd "$2;")
      (ok (buf= "foo-b[a]r-Baz")))))

(deftest vi-find-char-backward-after
  (with-fake-interface ()
    (with-vi-buffer ("foo-bar-Baz[z]")
      (cmd "T-")
      (ok (buf= "foo-bar-[B]azz"))
      (cmd "$Tb")
      (ok (buf= "foo-b[a]r-Bazz"))
      (cmd "$2T-")
      (ok (buf= "foo-[b]ar-Bazz"))
      (cmd "$3Ta")
      (ok (buf= "foo-bar-Baz[z]"))
      (cmd ";")
      (ok (buf= "foo-bar-Ba[z]z"))
      (cmd "$2;")
      (ok (buf= "foo-ba[r]-Bazz")))))

(deftest vi-search-forward-backward
  (with-fake-interface ()
    (with-vi-buffer (#?"[f]oo-bar-baz\nThis bar is great for gathering.\nCandy bars are my favorite food.\n")
      (cmd "/bar<Return>")
      (ok (buf= #?"foo-[b]ar-baz\nThis bar is great for gathering.\nCandy bars are my favorite food.\n"))
      (cmd "n")
      (ok (buf= #?"foo-bar-baz\nThis [b]ar is great for gathering.\nCandy bars are my favorite food.\n"))
      (cmd "N")
      (ok (buf= #?"foo-[b]ar-baz\nThis bar is great for gathering.\nCandy bars are my favorite food.\n"))
      (cmd "2n")
      (ok (buf= #?"foo-bar-baz\nThis bar is great for gathering.\nCandy [b]ars are my favorite food.\n"))
      (cmd "/apple<Return>")
      (ok (buf= #?"foo-bar-baz\nThis bar is great for gathering.\nCandy [b]ars are my favorite food.\n")))
    (with-vi-buffer (#?"foo-bar-baz\nThis bar is great for gathering.\nCandy bars are my favorite food[.]\n")
      (cmd "?bar<Return>")
      (ok (buf= #?"foo-bar-baz\nThis bar is great for gathering.\nCandy [b]ars are my favorite food.\n"))
      (cmd "n")
      (ok (buf= #?"foo-bar-baz\nThis [b]ar is great for gathering.\nCandy bars are my favorite food.\n"))
      (cmd "N")
      (ok (buf= #?"foo-bar-baz\nThis bar is great for gathering.\nCandy [b]ars are my favorite food.\n")))))

(deftest vi-move-to-matching-item
  (with-fake-interface ()
    (with-vi-buffer (#?"line 1\n[l]ine 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10")
      (cmd "10%")
      (ok (buf= #?"[l]ine 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10"))
      (cmd "20%")
      (ok (buf= #?"line 1\n[l]ine 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10"))
      (cmd "30%")
      (ok (buf= #?"line 1\nline 2\n[l]ine 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10"))
      (cmd "40%")
      (ok (buf= #?"line 1\nline 2\nline 3\n[l]ine 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10"))
      (cmd "50%")
      (ok (buf= #?"line 1\nline 2\nline 3\nline 4\n[l]ine 5\nline 6\nline 7\nline 8\nline 9\nline 10"))
      (cmd "60%")
      (ok (buf= #?"line 1\nline 2\nline 3\nline 4\nline 5\n[l]ine 6\nline 7\nline 8\nline 9\nline 10"))
      (cmd "70%")
      (ok (buf= #?"line 1\nline 2\nline 3\nline 4\nline 5\nline 6\n[l]ine 7\nline 8\nline 9\nline 10"))
      (cmd "80%")
      (ok (buf= #?"line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\n[l]ine 8\nline 9\nline 10"))
      (cmd "90%")
      (ok (buf= #?"line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\n[l]ine 9\nline 10"))
      (cmd "100%")
      (ok (buf= #?"line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\n[l]ine 10")))))

(deftest vi-move-to-matching-paren
  (with-fake-interface ()
    (with-vi-buffer (#?"abc[(]123)def\n")
      (cmd "%")
      (ok (buf= #?"abc(123[)]def\n"))
      (cmd "%")
      (ok (buf= #?"abc[(]123)def\n")))))